package com.xbongbong.saas.service.toolbox.help;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.enums.SheetTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.MathUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.enums.AmountFlagEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Map;
import java.util.Objects;

/**
 * 字段 小数精度控制 帮助类
 *
 * @author feng.zheng
 * @version v1.0
 * @date 2019/3/6 15:41
 * @since v1.0
 */
@Component
public class AttrDecimalPrecisionHelper {

    /**
     * 默认的小数精度:2
     */
    public static int DEFAULT_PRECISION = 2;

    /**
     * 支持最大的精度位数：6
     */
    public static int MAX_PRECISION = 6;

    /**
     * 设置钱币格式的 double值 精度 (#,##0.00 如 123,456,789.12 )
     *
     * @param value            值
     * @param decimalPrecision 小数位数
     * @return 钱币格式 #,##0.00
     * @version 3.25
     * @author zheng.li
     * @time 2018年7月4日 下午8:53:40
     * @updateTime 2018年7月4日 下午8:53:40
     * @since 3.25
     */
    public String formatMoneyPrecision(Double value, int decimalPrecision) {
        String result = "0";
        if (value == null) {
            return result;
        }
        String pattern = "##,##0.";
        if (Objects.equals(decimalPrecision, 0)) {
            pattern = "##,##0";
        }
        for (int i = 0; i < decimalPrecision; i++) {
            pattern = pattern + "0";
        }
        DecimalFormat df = new DecimalFormat(pattern);
        result = df.format(value);
        return result;
    }

    /**
     * 获取字段精度
     *
     * @param explainMap 解释
     * @param attr       需要设置的字段attr
     * @return java.lang.Integer
     * @author zcp
     * @date 19/11/12 012 15:38
     * @update 19/11/12 012 15:38
     * @version v1.0
     * @since v1.0
     */
    public Integer getAccuracy(Map<String, FieldAttrEntity> explainMap, String attr) {
        FieldAttrEntity fieldAttrEntity = explainMap.getOrDefault(attr, new FieldAttrEntity());
        Integer accuracy = fieldAttrEntity.getAccuracy();
        if (accuracy == null) {
            accuracy = DEFAULT_PRECISION;
        }
        return accuracy;
    }

    /**
     * 设置钱币格式的 double值 精度 (#,##0.00 如 123,456,789.12 )
     *
     * @param value      值
     * @param explainMap 解释
     * @param attr       需要设置的字段attr
     * @return 金额字符串
     */
    public String formatMoneyPrecision(Double value, Map<String, FieldAttrEntity> explainMap, String attr) {
        FieldAttrEntity amountField = explainMap.getOrDefault(attr, new FieldAttrEntity());
        Integer accuracy = amountField.getAccuracy();
        if (accuracy == null) {
            accuracy = DEFAULT_PRECISION;
        }
        return formatMoneyPrecision(value, accuracy);
    }

    /**
     * 设置钱币格式的 double值 精度 (#,##0.00 如 123,456,789.12 )
     *
     * @param value      值
     * @param fieldAttrEntity 解释实体
     * @return 金额字符串
     */
    public String formatMoneyPrecision(Double value, FieldAttrEntity fieldAttrEntity) {
        Integer accuracy = fieldAttrEntity.getAccuracy();
        if (accuracy == null) {
            accuracy = DEFAULT_PRECISION;
        }
        return formatMoneyPrecision(value, accuracy);
    }

    /**
     * 格式精度带整数
     *
     * @param value      值
     * @param fieldAttrEntity 解释实体
     * @return 金额字符串
     */
    public Object formatPrecisionWithIntegerOnly(Double value, FieldAttrEntity fieldAttrEntity) {
        if (value == null) {
            value = 0D;
        }
        Integer integerOnly = fieldAttrEntity.getIntegerOnly();
        if (Objects.nonNull(integerOnly) && Objects.equals(integerOnly, 1)) {
            return MathUtil.ceil(value, BasicConstant.ZERO);
        } else {
            return setPrecision(value, fieldAttrEntity.getAccuracy());
        }
    }

    /**
     * 设置钱币格式的 double值 (最大支持展示 6 位小数)
     *
     * @param value
     * @return
     * @version 3.24
     * @author zheng.li
     * @time 2018年7月4日 下午9:08:11
     * @updateTime 2018年7月4日 下午9:08:11
     * @since 3.24
     */
    public static String formatMoneyMaxPrecision(Double value) {
        String result = "0";
        if (value == null) {
            return result;
        }
        DecimalFormat decimalFormat = new DecimalFormat(",##0");
        decimalFormat.setMaximumFractionDigits(MAX_PRECISION);
        result = decimalFormat.format(value);
        return result;
    }


    /**
     * 设置double值的小数精度
     *
     * @param value      原值
     * @param explainMap 解释
     * @param attr       属性
     * @return 新值
     * @author zheng.li
     * @since 3.28
     */
    public Double setPrecision(Double value, Map<String, FieldAttrEntity> explainMap, String attr) {
        FieldAttrEntity amountField = explainMap.getOrDefault(attr, new FieldAttrEntity());
        Integer accuracy = amountField.getAccuracy();
        if (accuracy == null) {
            accuracy = DEFAULT_PRECISION;
        }
        return setPrecision(value, accuracy);
    }

    /**
     * 设置String 类型值的小数精度
     *
     * @param value            值
     * @param decimalPrecision 精度
     * @return 字符串
     * @author zheng.li
     * @since 3.28
     */
    public static String setPrecisionStr(String value, int decimalPrecision) {
        if (StringUtil.isEmpty(value)) {
            return "";
        }
        Double doubleValue;
        java.text.NumberFormat nf = java.text.NumberFormat.getInstance();
        try {
            // 不使用千分位，即展示为11672283.234，而不是11,672,283.234
            nf.setGroupingUsed(false);
            // 设置数的小数部分所允许的最小位数
            nf.setMinimumFractionDigits(0);
            // 设置数的小数部分所允许的最大位数
            nf.setMaximumFractionDigits(decimalPrecision);
            doubleValue = nf.parse(value).doubleValue();

        } catch (Exception e) {
            doubleValue = 0D;
        }
        return nf.format(doubleValue);
    }


    /**
     * 设置double值的小数精度
     *
     * @param value            原值
     * @param decimalPrecision 小数位数
     * @return 新值
     * @author zheng.li
     * @since 3.28
     */
    public Double setPrecision(Double value, Integer decimalPrecision) {
        if (value == null) {
            return 0D;
        }
        if(decimalPrecision == null) {
            decimalPrecision = DEFAULT_PRECISION;
        }
        Double resultValue;
        try {
            resultValue = Arith.round(value, decimalPrecision);
        } catch (IllegalArgumentException e) {
            //精度值不合理,返回原值
            resultValue = value;
        }
        return resultValue;
    }

    /**
     * 设置double值的小数精度
     *
     * @param value 原值
     * @param decimalPrecision 小数位数
     * @return
     * @throws
     * @author hongxiao
     * @date 2019-07-04 14:43
     * @since v1.0
     * @version v1.0
     */
    public String setDecPrecision(Double value, Integer decimalPrecision) {
        if (value == null) {
            value = 0D;
        }
        if(decimalPrecision == null) {
            decimalPrecision = DEFAULT_PRECISION;
        }
        // 格式化数字，小数部分不足时补0
        StringBuffer precisionFormat = new StringBuffer();
        for (int i = 0; i < decimalPrecision; i++) {
            precisionFormat.append("0");
        }

        String format = "#0" + StringConstant.POINT + precisionFormat;
        if (Objects.equals(decimalPrecision, 0)) {
            format = "#0";
        }
        DecimalFormat df = new DecimalFormat(format);
        // 四舍五入
        df.setRoundingMode(RoundingMode.HALF_UP);
        return df.format(value);
    }

    /**
     * 设置精度无千份位
     * @param value 值
     * @param decimalPrecision
     * @return
     */
    public static Double setDecimalPrecision(Object value,Integer decimalPrecision){
        if(Objects.isNull(value)){
            return 0D;
        }
        if(decimalPrecision == null){
            decimalPrecision = DEFAULT_PRECISION;
        }
        String pattern = "##0.";
        for (int i = 0; i < decimalPrecision; i++) {
            pattern = pattern + "0";
        }
        DecimalFormat df = new DecimalFormat(pattern);
        String result = df.format(Double.parseDouble(String.valueOf(value)));
        return Double.valueOf(result);
    }


    public static Object moneyParseThrousandth(FieldAttrEntity fieldAttrEntity, JSONObject data, String attr){
        Object contractAmount = data.get(attr);
        if(AmountFlagEnum.YES.getType().equals(fieldAttrEntity.getAmountFlag())){
            contractAmount = parseThousandth(contractAmount,fieldAttrEntity.getAccuracy());
        }else {
            contractAmount = setDecimalPrecision(contractAmount,fieldAttrEntity.getAccuracy());
        }
        return contractAmount;
    }
    /**
     * 金额千份位解析
     * @param value
     * @return
     */
    public static Object parseThousandth(Object value, Integer accuracy){
        if(Objects.isNull(value)){
            return value;
        }
        if (accuracy == null) {
            accuracy = BasicConstant.DEFAULT_ACCURACY;
        }
        String pattern = "##,##0.";
        if (Objects.equals(accuracy, 0)) {
            pattern = "##,##0";
        }
        for (int i = 0; i < accuracy; i++) {
            pattern = pattern + "0";
        }
        DecimalFormat df = new DecimalFormat(pattern);
        if(value instanceof Integer || value instanceof Double ||
                value instanceof BigDecimal || value instanceof Long || StringUtil.isDigital(value.toString())){
            return df.format(Double.parseDouble(String.valueOf(value)));
        }
        return value;
    }

    /**
     * 获取格式化的数字字符串
     *
     * @param value    值
     * @param accuracy 小数精度
     * @param groupUsed 是否使用千分符
     * @param percentUsed 是否使用百分比
     * @return 格式化后的字符串
     * @author zheng.li
     * @since BI
     */
    public String getNumberFormat(String value, int accuracy,Integer groupUsed,Integer percentUsed) {
        if (StringUtil.isEmpty(value)) {
            return "";
        }
        BigDecimal bigDecimal;
        try {
            bigDecimal = new BigDecimal(value);
        } catch (Exception e) {
            //不能转成BigDecimal时返回空
            return  "";
        }
        // 将科学计数法转换成数字类型
        value = bigDecimal.toPlainString();
        double doubleValue;
        boolean isGroupUsed = Objects.equals(1,groupUsed);
        java.text.NumberFormat nf = java.text.NumberFormat.getInstance();
        try {
            if (Objects.equals(percentUsed,1)) {
                //使用百分比
                NumberFormat pnf  =  NumberFormat.getPercentInstance();
                pnf.setGroupingUsed(isGroupUsed);
                pnf.setMaximumFractionDigits(accuracy);
                pnf.setMinimumFractionDigits(accuracy);
                return pnf.format(Double.valueOf(value));
            } else {
                // 是否使用千分位，即展示为11672283.234，而不是11,672,283.234
                nf.setGroupingUsed(isGroupUsed);
                // 设置数的小数部分所允许的最小位数
                nf.setMinimumFractionDigits(accuracy);
                // 设置数的小数部分所允许的最大位数
                nf.setMaximumFractionDigits(accuracy);
                doubleValue = nf.parse(value).doubleValue();
            }

        } catch (Exception e) {
            doubleValue = 0D;
        }
        return nf.format(doubleValue);
    }

    /**
     * 获取精度下最小数
     * @param accuracy
     * @return
     */
    public Double getMixNum(Integer accuracy) {
        return Math.pow(10,-accuracy);
    }

    /**
     * 获取精度下的数据，不进行四舍五入
     * 会返回科学计数法，需要直接展示出来的话调用setPrecisionNotRoundStr
     * @param value
     * @param accuracy
     * @return
     */
    public Double setPrecisionNotRound(Double value, int accuracy) {

        if (Objects.isNull(value)) {
            return null;
        }
        String formatValue = setPrecisionNotRoundStr(value, accuracy);
        BigDecimal bigDecimal = new BigDecimal(formatValue);
        return bigDecimal.doubleValue();
    }
    /**
     * 获取精度下的数据，不进行四舍五入
     * @param value
     * @param accuracy
     * @return 返回字符串
     */
    public String setPrecisionNotRoundStr(Double value, int accuracy) {
        if (Objects.isNull(value)) {
            return null;
        }

        DecimalFormat decimalFormat = new DecimalFormat();

        //设置某个数的小数部分中所允许的最大数字位数
        decimalFormat.setMaximumFractionDigits(accuracy);
        // 不使用千分位，即展示为11672283.234，而不是11,672,283.234
        decimalFormat.setGroupingUsed(false);
        //此舍入模式始终不会增加计算值。
        decimalFormat.setRoundingMode(RoundingMode.FLOOR);
        String formatValue = decimalFormat.format(value);
        return formatValue;
    }
    
    /**
     * 得到回款單的回款金額（核銷金額）同时处理精度
     * @param writeOffAmount 回款金额
     * @param paymentSheetType 回款單類型
     * @return java.lang.Double
     * @author chenshan
     * @since v1.0
     * @version v1.0
     */
    public String getSheetAmountDealAccuracy(Map<String, FieldAttrEntity> explainMap, Double writeOffAmount, String paymentSheetType) {
        Integer accuracy = DEFAULT_PRECISION;
        String attr = PaymentSheetEnum.WRITE_OFF_AMOUNT.getAttr();
        if (SheetTypeEnum.onlyWriteOffAmount(paymentSheetType)) {
            //預收款核銷、红冲预收款核销(退到余额)則讀取核銷金額
            attr = PaymentSheetEnum.WRITE_OFF_AMOUNT.getAttr();
        }
        FieldAttrEntity amountField = explainMap.getOrDefault(attr, new FieldAttrEntity());;
        if (accuracy != null) {
            accuracy = amountField.getAccuracy();
        }
        return formatMoneyPrecision(writeOffAmount, accuracy);
    }

    /**
     * 设置double值的小数精度
     *
     * @param value 原值
     * @param accuracy 小数位数
     * @return
     * @throws
     * @author hongxiao
     * @date 2019-07-04 14:43
     * @since v1.0
     * @version v1.0
     */
    public static String setNumAccuracy(Double value, Integer accuracy, Integer amountFlag, Integer integerOnly) {
        String str ="";
        if (integerOnly == 1) {
            accuracy = 0;
        }
        if(Objects.isNull(value)){
            return str;
        }
        if(accuracy == null) {
            accuracy = DEFAULT_PRECISION;
        }
        if (AmountFlagEnum.YES.getType().equals(amountFlag)) {
            String pattern = "##,##0.";
            if (Objects.equals(accuracy, 0)) {
                pattern = "##,##0";
            }
            for (int i = 0; i < accuracy; i++) {
                pattern = pattern + "0";
            }
            DecimalFormat df = new DecimalFormat(pattern);
            str = df.format(Double.parseDouble(String.valueOf(value)));
        } else {
            Double resultValue;
            try {
                resultValue = Arith.round(value, accuracy);
            } catch (IllegalArgumentException e) {
                //精度值不合理,返回原值
                resultValue = value;
            }
            str =resultValue.toString();
        }
        return str;
    }

    /**
     * 设置double值的小数精度
     *
     * @param value            原值
     * @param decimalPrecision 小数位数
     * @return 新值
     * @author zheng.li
     * @since 3.28
     */
    public static Double setMallPrecision(Double value, Integer decimalPrecision) {
        if (value == null) {
            return 0D;
        }
        if(decimalPrecision == null) {
            decimalPrecision = DEFAULT_PRECISION;
        }
        Double resultValue;
        try {
            resultValue = Arith.round(value, decimalPrecision);
        } catch (IllegalArgumentException e) {
            //精度值不合理,返回原值
            resultValue = value;
        }
        return resultValue;
    }
}
